#ifdef __APPLE__
	#include <OpenGL/gl.h>
	#include <OpenGL/glu.h>
	#include <OpenGL/OpenGL.h>
#else
	#include <GL/gl.h>
	#include <GL/glext.h>
	#include <GL/glu.h>
#endif

//#include "png.h"
//#include "jpeglib.h"

#include <ruby.h>

VALUE rbas_image;


long
image_memory(int numbytes, void *data_ptr)
{
	volatile VALUE data = rb_str_new(NULL, 0);
	rb_str_resize(data, numbytes);
	(*((void **)data_ptr)) = StringValuePtr(data);
	
	return data;
}

void
throw_error(char *filename, char *error)
{
	rb_raise(rb_eRuntimeError, "AS::Image(%s) %s", filename, error);
}


extern long load_png(char *name, int rgb, int alpha, int premult, int *width, int *height);
extern long load_jpeg(char *filename, int *width, int *height);


static VALUE
rbas_loadPNG_RGBA(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 1, 1, 0, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_RGBA));
}

static VALUE
rbas_loadPNG_RGBA_pre(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 1, 1, 1, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_RGBA));
}

static VALUE
rbas_loadPNG_RGB(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 1, 0, 0, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_RGB));
}

static VALUE
rbas_loadPNG_LUM(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 0, 0, 0, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_LUMINANCE));
}

static VALUE
rbas_loadPNG_LUM_AS_ALPHA(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 0, 0, 0, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_ALPHA));
}

static VALUE
rbas_loadPNG_LUMA(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 0, 1, 0, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_LUMINANCE_ALPHA));
}

static VALUE
rbas_loadPNG_LUMA_pre(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_png(StringValuePtr(filename), 0, 1, 1, &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_LUMINANCE_ALPHA));
}

static VALUE
rbas_loadJPEG_RGB(VALUE self, VALUE filename)
{
	int w, h;
	volatile VALUE data = load_jpeg(StringValuePtr(filename), &w, &h);
	
	return rb_struct_new(rbas_image, data, INT2FIX(w), INT2FIX(h), INT2NUM(GL_RGB));
}

static VALUE
rbas_screen_shot(VALUE self, VALUE filename)
{
//	int bytes = AS_SCREEN_W * AS_SCREEN_H * 3;
//	GLubyte pixels[bytes];
//	glReadPixels(0, 0, AS_SCREEN_W, AS_SCREEN_H, GL_RGB, GL_UNSIGNED_BYTE, pixels);
//	
//	char *name = StringValuePtr(filename);
//	FILE *png_file = fopen(name, "wb");
//	if(!png_file)
//		rb_raise(rb_eRuntimeError, "\"%s\" could not be opened for writing.", name);
//	
//	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
//	if(!png_ptr)
//		rb_raise(rb_eRuntimeError, "LibPNG error when saving \"%s\".", name);
//
//	
//	png_infop info_ptr = png_create_info_struct(png_ptr);
//	if(!info_ptr)
//		rb_raise(rb_eRuntimeError, "LibPNG error when saving \"%s\".", name);
//	
//	if(setjmp(png_jmpbuf(png_ptr)))
//		rb_raise(rb_eRuntimeError, "LibPNG error when saving \"%s\".", name);
//
//	png_init_io(png_ptr, png_file);
//	
//	png_set_IHDR(png_ptr, info_ptr, AS_SCREEN_W, AS_SCREEN_H,
//	             8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
//	             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
//	
//	png_byte* row_ptrs[AS_SCREEN_H];
//	
//	int i;
//	for (i=0; i<AS_SCREEN_H; i++)
//		row_ptrs[i] = pixels + (AS_SCREEN_H - 1 - i)*(AS_SCREEN_W*3);
//	
//	png_set_rows(png_ptr, info_ptr, row_ptrs);
//	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
//	
//	png_destroy_write_struct(&png_ptr, &info_ptr);
//	fclose(png_file);
	
	return Qnil;
}

static VALUE
rbas_getScreen(VALUE self)
{
	VALUE out_str = rb_str_new(NULL, 0);
//	rb_str_resize(out_str, AS_SCREEN_W*AS_SCREEN_H*4);
//	
//	glReadPixels(0, 0, AS_SCREEN_W, AS_SCREEN_H, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte *)RSTRING(out_str)->ptr);
	
	
	return out_str;
}

void Init_AS_Image(void)
{
	VALUE m_AS = rb_define_module("AS");
	rbas_image = rb_eval_string("AS::Image = Struct.new(:data, :w, :h, :format)");

	rb_define_module_function(rbas_image, "load_png_rgba", &rbas_loadPNG_RGBA, 1);
	rb_define_module_function(rbas_image, "load_png_rgba_premult", &rbas_loadPNG_RGBA_pre, 1);
	rb_define_module_function(rbas_image, "load_png_rgb", &rbas_loadPNG_RGB, 1);
	rb_define_module_function(rbas_image, "load_png_lum", &rbas_loadPNG_LUM, 1);
	rb_define_module_function(rbas_image, "load_png_lum_as_alpha", &rbas_loadPNG_LUM_AS_ALPHA, 1);
	rb_define_module_function(rbas_image, "load_png_luma", &rbas_loadPNG_LUMA, 1);
	rb_define_module_function(rbas_image, "load_png_luma_premult", &rbas_loadPNG_LUMA_pre, 1);
	
	rb_define_module_function(rbas_image, "load_jpeg_rgb", &rbas_loadJPEG_RGB, 1);
	
	rb_define_module_function(rbas_image, "screen_shot", &rbas_screen_shot, 1);
	rb_define_module_function(rbas_image, "get_screen", &rbas_getScreen, 0);
}
